/********************************************************************
	created:	2010/07/13
	created:	13:7:2010   17:10
	filename: 	D:\Proj\gcstock\code\C++\GCStock\Stock\GCStock.cpp
	file path:	D:\Proj\gcstock\code\C++\GCStock\Stock
	file base:	GCStock
	file ext:	cpp
	author:		Greg Song
	
	purpose:	
*********************************************************************/
#include "GCHeader.h"
#include "GCStock.h"
#include "GCData.h"
#include "GCString.h"

namespace gcstock
{
    GCCHAR formatStrQQ[] = _GCT("v_$exchange#2$$stock_code$=\"$exchange_code$~$stock_name$~$stock_code$~$current_trade$~$last_trade$~$open$~$turnover$~$fbuyprice$~$fsellprice$~$sell_price1$~$sell1$~$sell_price2$~$sell2$~$sell_price3$~$sell3$~$sell_price4$~$sell4$~$sell_price5$~$sell5$~$buy_price1$~$buy1$~$buy_price2$~$buy2$~$buy_price3$~$buy3$~$buy_price4$~$buy4$~$buy_price5$~$buy5$~$detail_trade$~$current_time$~$change$~$change_ratio$~$highest_price$~$lowest_price$~~$turnover$~$volume_of_business$~$turnover_rate$~$pe_ratio$~~$highest_price$~$lowest_price$~$swing$~$market_value$~$float$~~$floor$~$high_limit$~\"");
    const static GCCHAR varTag = _GCT('$');
    const static GCCHAR fixTag = _GCT('#');
    const static GCCHAR arrTag = _GCT('%');


    const GCTradeRec* GCDetailTradeQQ::operator [](GCINT index)
    {
        if(index < recList.getLen())
        {
            return recList[index];
        }
        return NULL; 
    }
    
    GCTestString GCDetailTradeQQ::toString()
    {
        GCSStream str;
        
        for(int i = 0; i < recList.getLen(); ++i)
        {
            GCTradeRec* pRec = recList[i];
            str<<pRec->time.toString();
            str<< _GCT(' ');
            
            str<<pRec->price;
            str<< _GCT(' ');
            
            str<<pRec->unit;
            str<< _GCT(' ');
            
            str<<((pRec->action == 1)?_GCT('B'):_GCT('S'));
            str<<_GCT(' ');
            
            str<<pRec->amount;
            str<<gcendl;
        }
        return str.str();
    }
    
    void GCDetailTradeQQ::add(GCCHAR* recs)
    {
        GCVArray<GCCHAR*> strArray;
        splitW(_GCT('|'),recs, strArray);

        int curSeq = lastSeq;
        for(int i = 0; i<strArray.getLen();++i)
        {
            GCVArray<GCCHAR*> array;
            splitW(_GCT('/'),strArray[i],array);       
            
            int seq = GCSTRTOL(array[5], NULL, 10);
            
            if(seq > lastSeq)
            {
                if(seq > curSeq)
                {
                    curSeq = seq;                    
                }

                GCTradeRec* pTrade = new GCTradeRec;
                pTrade->time = GCTimestamp::convertToStamp(array[0], _GCT(':'));
                
                pTrade->price = GCFloat::fromStrToFloat(array[1]);
                
                pTrade->unit = GCSTRTOL(array[2],NULL, 10);
                
                pTrade->action = (*(array[3]) == _GCT('B'))?1:0;
                
                pTrade->amount = GCSTRTOL(array[4], NULL, 10);
                
                pTrade->seq = seq;  

                recList.add(pTrade);
            }  
            else
            {
                // gccout<<_GCT("old data! pass it!")<<gcendl;
            }
        }

        lastSeq = curSeq;

        if(recList.getLen() > updateLimit)
        {
            insertIntoDB();
        }
        
    }
    
    void GCDetailTradeQQ::insertIntoDB()
    {
        
    }

   void GCStockMonitorQQ::setParseFormat()
   {
       int size = 0;
       parseFormat(formatStrQQ,size);
   }
    
    void GCStockMonitorQQ::parseFormat(IN GCCHAR* format, OUT GCINT& size)
    {
        int length = GCSTRLEN(format) ;
        int i;
        size = 0;
        
        GCBOOL bIsKey = FALSE;
        
        // I didn't consider overflow
        GCCHAR varName[32] = {_GCT("")}; 
        GCINT varLen = 0;
        
        GCCHAR prefix[32] = {_GCT("")};
        GCINT  prefixLen = 0;
        
        GCCHAR fixedLenC[32] = {_GCT("")};
        GCINT  fixedLenCLen = 0;
        
        GCBOOL fixed = FALSE;
        int fixedLen = 0;
        for(i = 0; i<length;++i)
        {
            switch(format[i])
            {
            case varTag:
                {
                    if(bIsKey)
                    {
                        //varName[varLen++] = format[i]; 
                        varName[varLen] = _GCT('\0');
                        prefix[prefixLen] = _GCT('\0');
                        
                        GCParseElement * pair = new GCParseElement;
                        int len = GCSTRLEN(varName);
                        
                        pair->key = new GCCHAR[len + 1];
                        memcpy(pair->key, varName, len + 1);
                        
                        pair->type = GC_TYPE_WSTRING ;
                        
                        int preLen = GCSTRLEN(prefix);
                        
                        pair->prefix = new GCCHAR[preLen + 1];
                        memcpy(pair->prefix, prefix, preLen + 1);
                        
                        if(fixed)
                        {
                            fixedLenC[fixedLenCLen] = _GCT('\0');
                            pair->bIsFixedLength = TRUE;
                            pair->fixedLength = GCSTRTOL(fixedLenC,NULL,10);
                            fixed = FALSE;
                        }
                        
                        arrayParsed.add(pair);
                        varLen = 0;
                        prefixLen = 0;
                        bIsKey = FALSE;
                    }
                    else
                    {
                        bIsKey = TRUE;
                    }
                }
                break;
            case fixTag:
                {
                    if(bIsKey)
                    {
                        fixed = TRUE;
                    }
                    else
                    {
                        // error
                    }
                }
                break;
            case arrTag:
                {
                    if(bIsKey)
                    {
                        // raise error
                    }
                    //parseArray(&format[i - prefixLen],size);
                    prefixLen = 0;
                    i += size - 1;
                }
                break;
            default:
                {
                    if(bIsKey)
                    {
                        varName[varLen++] = format[i];   
                        if(fixed)
                        {
                            fixedLenC[fixedLenCLen++] = format[i];
                        }
                    }
                    else
                    {
                        prefix[prefixLen++] = format[i];
                    }
                }
                break;
            }
        }

        if(prefixLen)
        {
            varName[varLen] = _GCT('\0');
            prefix[prefixLen] = _GCT('\0');
            
            GCParseElement * pair = new GCParseElement;
            int len = GCSTRLEN(varName);
            
            pair->key = new GCCHAR[len + 1];
            memcpy(pair->key, varName, len + 1);
            
            pair->type = GC_TYPE_WSTRING ;
            
            int preLen = GCSTRLEN(prefix);
            
            pair->prefix = new GCCHAR[preLen + 1];
            memcpy(pair->prefix, prefix, preLen + 1);
            
            if(fixed)
            {
                fixedLenC[fixedLenCLen] = _GCT('\0');
                pair->bIsFixedLength = TRUE;
                pair->fixedLength = GCSTRTOL(fixedLenC,NULL,10);
                fixed = FALSE;
            }
            
            arrayParsed.add(pair);
            varLen = 0;
            prefixLen = 0;
            bIsKey = FALSE;
        }       
    }

    void GCStockMonitorQQ::parseLine(IN GCCHAR* rawData)
    {
        int length = GCSTRLEN(rawData) ;
        int i, idx = 0;
        //gccout<<rawData<<gcendl;
        GCBOOL bIsKey = FALSE;
        
        // I didn't consider overflow
        GCCHAR value[32] = {_GCT("")}; 
        GCINT varLen = 0;
        
        GCCHAR prefix[32] = {_GCT("")};
        GCINT  prefixLen = 0;
        GCStock* pStock = NULL;
        // check the prefix then get the value
        for(i = 0;i<arrayParsed.getLen(),idx<length; ++i)
        {
            int j = 0;
            while(arrayParsed[i]->prefix[j] != _GCT('\0'))
            {
                j++;
            }
            if(0 == GCSTRNCMP(&rawData[idx],arrayParsed[i]->prefix,j))
            {                
                GCCHAR tmp = rawData[idx + j];
                rawData[idx + j] = _GCT('\0');
                // prefix
                
                rawData[idx + j] = tmp;
                idx += j;
            }
            else
            {
                
            }
            
            int k = 0;
            if(arrayParsed[i]->bIsFixedLength)
            {
                GCCHAR tmp = rawData[idx + arrayParsed[i]->fixedLength];
                rawData[idx + arrayParsed[i]->fixedLength] = _GCT('\0');
                
                rawData[idx + arrayParsed[i]->fixedLength] = tmp;  
                idx += arrayParsed[i]->fixedLength;
                continue;
            }
            if(i + 1 >= arrayParsed.getLen())
            {
                break;
            }
            int dataLen = GCSTRLEN(rawData);
            while((idx + k) < dataLen)
            {   
                int l = 1;
                GCBOOL found = FALSE;
                while((idx+k+l<dataLen)&&
                    i+1 < arrayParsed.getLen()&&
                    rawData[idx + k + l] != arrayParsed[i+1]->prefix[0])
                {
                    l++;
                }
                if(idx+k+l >= dataLen)
                {
                    // error
                }
                k += l;
                l = 0;
                while((idx+k+l<dataLen)&&
                    i+1 < arrayParsed.getLen()&&
                    rawData[idx + k + l] == arrayParsed[i+1]->prefix[l])
                {
                    l++;
                }
                int preLen =  GCSTRLEN(arrayParsed[i+1]->prefix);
                if(l == GCSTRLEN(arrayParsed[i+1]->prefix))
                {
                    GCCHAR tmp = rawData[idx + k];
                    rawData[idx + k] = _GCT('\0');
                    
                    if(GCSTRCMP(arrayParsed[i]->key,_GCT("detail_trade\0")) == 0)
                    {
                        pStock->add(&rawData[idx]);
                    }
                    else if(GCSTRCMP(arrayParsed[i]->key,_GCT("stock_code\0")) == 0)
                    {
                        GCINT code = GCSTRTOL(&rawData[idx],NULL,10);
                        
                        pStock = operator[](code);
                        if(!pStock)
                        {    
                            pStock = new GCStock;
                            pStock->setCode(code);
                            stockArray.add(pStock);
                        }                        
                    }
                    else if(GCSTRCMP(arrayParsed[i]->key,_GCT("stock_name\0")) == 0)
                    {
                        if(pStock)
                        {
                            pStock->setName(&rawData[idx]);
                        }
                    }
                    else if(GCSTRCMP(arrayParsed[i]->key,_GCT("market_value\0")) == 0)
                    {
                        GCFLOAT total_amount = GCFloat::fromStrToFloat(&rawData[idx]);
                        if(pStock)
                        {
                            pStock->setTotalAmt(total_amount);
                        }
                    }
                    else if(GCSTRCMP(arrayParsed[i]->key,_GCT("current_trade\0")) == 0)
                    {
                        GCFLOAT price = GCFloat::fromStrToFloat(&rawData[idx]);
                        if(pStock)
                        {
                            pStock->setPrice(price);
                        }
                    }

                    rawData[idx + k] = tmp;  
                    idx += k ;
                    break;
                }
                else
                {
                    k++;
                }
            }
        }
    }


    // Access method
    // By code
    GCStock* GCStockMonitorQQ::operator[](GCINT code)
    {
        int i;
        for(i=0;i<stockArray.getLen();++i)
        {
            if(code == stockArray[i]->getCode())
            {
                return stockArray[i];
            }
        }
        return NULL;
    }
    
    // By name
    GCStock* GCStockMonitorQQ::operator[](GCCHAR* name)
    {
        int i;
        for(i=0;i<stockArray.getLen();++i)
        {
            if(GCSTRCMP(name,stockArray[i]->getName()))
            {
                return stockArray[i];
            }
        }
        return NULL;
    }
}